#pragma once

#include <TopoDS_Shape.hxx>
#include <gp_Ax2.hxx>

enum class EFeatureType : uint8_t
{
	// 无形状
	None = 0,
	// 混合
	Mix,
	ArcCircle,
	Cone,
	Cylinder,
	Ellipse,
	Hyperbola,
	Line,
	Parabola,
	Sphere,
	Torus,
	Cube,
	Circle,
	Rectangle,
};

// 含有特征值的形状，能够创造出一个pipeline
// 支持序列化与反序列化
class FeatureShape
{
public:
	FeatureShape() {}
    FeatureShape(const TopoDS_Shape& shape) : _shape(shape){}

	// 这个不会参与序列化与反序列化
	// 理论上序列化与反序列化的时候，使用到_shape的时候，这个都可以通过内部参数构建出来，Mix不是简单地通过一步创建出来的
	TopoDS_Shape _shape;
	// 这个会参与序列化，但是是在构造函数中自动赋值的，不会参与反序列化，会在使用工厂模式创建对象时，决定对象的类型
	EFeatureType _featureType = EFeatureType::None;
	gp_Pnt _position;

	// 序列化函数
	virtual void serialize(std::ofstream& out) const = 0;
	// 反序列化函数
	virtual void deserialize(std::ifstream& in) = 0;
	
	virtual bool IsEqual(const FeatureShape& other) const;
};

class FeatureShapeMix : public FeatureShape
{
public:
	FeatureShapeMix() { _featureType = EFeatureType::Mix; };
	FeatureShapeMix(const TopoDS_Shape& shape) : FeatureShape(shape)
	{
		_featureType = EFeatureType::Mix;
	}
	FeatureShapeMix(const TopoDS_Shape& shape, const std::string& filename) : FeatureShape(shape)
	{
		_featureType = EFeatureType::Mix;
		_shapeFileName = filename;
	}

	std::string _shapeFileName = "None";

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeArcCircle : public FeatureShape
{
public:
    FeatureShapeArcCircle() { _featureType = EFeatureType::ArcCircle; };
	FeatureShapeArcCircle(const TopoDS_Shape& shape, const gp_Pnt& start, const gp_Pnt& tangent, const gp_Pnt& end);

    gp_Pnt _start;
    gp_Pnt _tangent;
    gp_Pnt _end;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeCone : public FeatureShape
{
public:
    FeatureShapeCone() { _featureType = EFeatureType::Cone; };
	FeatureShapeCone(const TopoDS_Shape& shape, float radius1, float radius2, float height);
	// radius down
    float _radius1 = 0.f;
	// radius up
	float _radius2 = 0.f;
    float _height = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeCylinder : public FeatureShape
{
public:
    FeatureShapeCylinder() { _featureType = EFeatureType::Cylinder; };
	FeatureShapeCylinder(const TopoDS_Shape& shape, float radius, float height);

    float _radius = 0.f;
    float _height = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeEllipse : public FeatureShape
{
public:
    FeatureShapeEllipse() { _featureType = EFeatureType::Ellipse; };
	FeatureShapeEllipse(const TopoDS_Shape& shape, const gp_Ax2& axis, float majorRadius, float minorRadius);

    gp_Ax2 _axis;
    float _majorRadius = 0.f;
	float _minorRadius = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeHyperbola : public FeatureShape
{
public:
    FeatureShapeHyperbola() { _featureType = EFeatureType::Hyperbola; };
    FeatureShapeHyperbola(const TopoDS_Shape& shape, const gp_Ax2& axis, float majorRadius, float minorRadius, float startLen, float endLen);

    gp_Ax2 _axis;
    float _majorRadius = 0.f;
    float _minorRadius = 0.f;
    float _startLen = 0.f;
    float _endLen = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeLine : public FeatureShape
{
public:
    FeatureShapeLine() { _featureType = EFeatureType::Line; };
	FeatureShapeLine(const TopoDS_Shape& shape, const gp_Pnt& start, const gp_Pnt& end);

    gp_Pnt _start;
    gp_Pnt _end;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeParabola : public FeatureShape
{
public:
    FeatureShapeParabola() { _featureType = EFeatureType::Parabola; };
	FeatureShapeParabola(const TopoDS_Shape& shape, const gp_Ax2& axis, float focal, float startLen, float endLen);

    gp_Ax2 _axis;
    float _focal = 0.f;
    float _startLen = 0.f;
    float _endLen = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeSphere : public FeatureShape
{
public:
    FeatureShapeSphere() { _featureType = EFeatureType::Sphere; };
	FeatureShapeSphere(const TopoDS_Shape& shape, float radius) : FeatureShape(shape)
	{
		_featureType = EFeatureType::Sphere;
		_radius = radius;
	}

    float _radius = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeTorus : public FeatureShape
{
public:
    FeatureShapeTorus() { _featureType = EFeatureType::Torus; };
	FeatureShapeTorus(const TopoDS_Shape& shape, float radiusOuter, float radiusInner);

    float _radiusOuter = 0.f;
	float _radiusInner = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeCube : public FeatureShape
{
public:
    FeatureShapeCube() { _featureType = EFeatureType::Cube; };
	FeatureShapeCube(const TopoDS_Shape& shape, float length, float width, float height);

	float _length = 0.f;
	float _width = 0.f;
	float _height = 0.f;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeRectangle : public FeatureShape
{
public:
    FeatureShapeRectangle() { _featureType = EFeatureType::Rectangle; };
	FeatureShapeRectangle(const TopoDS_Shape& shape, const gp_Pnt& p1, const gp_Pnt& p2,
		const gp_Pnt& p3, const gp_Pnt& p4);

	gp_Pnt _p1;
    gp_Pnt _p2;
    gp_Pnt _p3;
    gp_Pnt _p4;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeCircle : public FeatureShape
{
public:
    FeatureShapeCircle() { _featureType = EFeatureType::Circle; };
	FeatureShapeCircle(const TopoDS_Shape& shape, const gp_Pnt& center, float radius, const gp_Dir& normal);

    float _radius = 0.f;
    gp_Pnt _center;
    gp_Dir _normal;

	virtual void deserialize(std::ifstream& in) override;
	virtual void serialize(std::ofstream& out) const override;

	virtual bool IsEqual(const FeatureShape& other) const override;
};

class FeatureShapeFactory
{
public:
    static std::shared_ptr<FeatureShape> CreateFeatureShape(EFeatureType featureType);
};